package com.imooc.bilibili.aspect;

import com.imooc.bilibili.annotation.ApiLimitedRole;
import com.imooc.bilibili.domain.auth.UserRole;
import com.imooc.bilibili.exception.ConditionException;
import com.imooc.bilibili.service.UserRoleService;
import com.imooc.bilibili.support.UserSupport;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 切面类
 *
 * @author xiexu
 * @create 2022-06-17 07:37
 */
@Aspect // 表明这是一个切面类
@Order(1) // 优先级
@Component // 让spring容器扫描到
public class ApiLimitedRoleAspect {

    @Autowired
    private UserSupport userSupport;

    /**
     * 用户关联角色
     */
    @Autowired
    private UserRoleService userRoleService;

    /**
     * 切点
     */
    @Pointcut("@annotation(com.imooc.bilibili.annotation.ApiLimitedRole)")
    public void check() {
    }

    /**
     * 前置通知
     *
     * @param joinPoint
     * @param apiLimitedRole
     */
    @Before("check() && @annotation(apiLimitedRole)")
    public void doBefore(JoinPoint joinPoint, ApiLimitedRole apiLimitedRole) {
        Long userId = userSupport.getCurrentUserId();
        // 获取用户相关的角色列表（用户具有哪些角色）
        List<UserRole> userRoleList = userRoleService.getUseRoleByUserId(userId);
        // 获取角色权限相关的唯一编码列表（对应AuthRole类的code字段）
        String[] limitedRoleCodeList = apiLimitedRole.limitedRoleCodeList();
        // 将角色权限的唯一编码列表转换成set集合
        Set<String> limitedRoleCodeSet = new HashSet<>();
        for (String s : limitedRoleCodeList) {
            limitedRoleCodeSet.add(s);
        }
        // 用户角色列表转换成set集合
        Set<String> roleCodeSet = new HashSet<>();
        for (UserRole userRole : userRoleList) {
            roleCodeSet.add(userRole.getRoleCode());
        }
        // 对用户角色列表 和 角色权限唯一编码列表 取交集，roleCodeSet存放的就是他们的交集
        roleCodeSet.retainAll(limitedRoleCodeSet);
        // 交集指的就是用户角色列表里面有包含，角色权限唯一编码列表里面也有包含，说明用户有某个角色是不允许被访问的
        if (roleCodeSet.size() > 0) {
            throw new ConditionException("权限不足！");
        }
    }

}
